package com.unicdata.ai.demo_2af.common.config;

import com.unicdata.ai.demo_2af.common.filters.CustomAuthFilter;
import com.unicdata.ai.demo_2af.service.UserService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * shiro 配置
 *
 * @author lhn
 * @date 2025/06/25 16:48
 * @since 1.0.0
 **/
@Configuration
@ConfigurationProperties(prefix = "shiro")
@Data
@Slf4j
public class ShiroConfig {

    private List <String> anonUrls;

    private String loginUrl;

    private String successUrl;

    private String unauthorizedUrl;

    /**
     * 凭证匹配器
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        // 设置散列算法：SHA-256
        credentialsMatcher.setHashAlgorithmName("SHA-256");
        // 设置散列次数：1024次
        credentialsMatcher.setHashIterations(1024);
        return credentialsMatcher;
    }

    /**
     * 自定义Realm
     */
    @Bean
    public UserRealm userRealm(UserService userService, HashedCredentialsMatcher matcher) {
        UserRealm userRealm = new UserRealm(userService);
        userRealm.setCredentialsMatcher(matcher);
        return userRealm;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager(UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * Shiro过滤器工厂
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl(loginUrl);
        shiroFilterFactoryBean.setSuccessUrl(successUrl);
        shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);

        // 配置拦截器链
        Map <String, String> filterChainDefinitionMap = new LinkedHashMap <>();
        log.info("发行白名单:{}", anonUrls);
        // 配置不需要拦截的链接
        if (anonUrls != null && !anonUrls.isEmpty()) {
            for (String anonUrl : anonUrls) {
                filterChainDefinitionMap.put(anonUrl, "anon");
            }
        }
        filterChainDefinitionMap.put("/api/user/**", "anon");
        // 配置退出过滤器，具体的退出代码Shiro已经实现
        filterChainDefinitionMap.put("/logout", "logout");

        // 其他请求需要认证
        filterChainDefinitionMap.put("/**", "authc");


        // 2fa
        filterChainDefinitionMap.put("/2fa/setup", "authc");
        filterChainDefinitionMap.put("/2fa/enable", "authc");
        filterChainDefinitionMap.put("/2fa/verify", "authc");


        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        // 注册自定义过滤器
        Map<String, javax.servlet.Filter> filters = new LinkedHashMap<>();
        filters.put("customAuthc", new CustomAuthFilter());
        shiroFilterFactoryBean.setFilters(filters);


        filterChainDefinitionMap.forEach((k, v) -> {
            System.out.println("Shiro 路径匹配规则：" + k + " -> " + v);
        });

        shiroFilterFactoryBean.getFilters().forEach((k, v) -> {
            System.out.println("注册的过滤器：" + k + " -> " + v.getClass().getSimpleName());
        });

        return shiroFilterFactoryBean;
    }

    /**
     * 开启Shiro注解模式
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}